﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Check_Barcode
{
    public class myEncoder
    {
        static string[] CODES = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                               "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
                               "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                               "U", "V", "W", "X", "Y", "Z", "-", "." };
        
        static int RADIX = CODES.Length;
        static int[] BASE38_CHARS_NEEDED_IN_CHUNK = new int[] { 2, 4, 5 };
        static int MAX_BYTES_IN_CHUNK = 3;
        static int MAX_ENCODED_BYTES_IN_CHUNK = 5;

        public static string Encode(byte[] bytes)
        {
            StringBuilder qrcode = new StringBuilder();

            for (int i = 0; i < bytes.Length; i += MAX_BYTES_IN_CHUNK)
            {
                int bytesInChunk = Math.Min(MAX_BYTES_IN_CHUNK, bytes.Length - i);
                int value = 0;

                for (int j = 0; j < bytesInChunk; j++)
                {
                    value = (value << 8) | bytes[i + j];
                }

                int base38CharsNeeded = BASE38_CHARS_NEEDED_IN_CHUNK[bytesInChunk - 1];
                while (base38CharsNeeded > 0)
                {
                    qrcode.Append(CODES[(int)(value % RADIX)]);
                    value /= RADIX;
                    base38CharsNeeded--;
                }
            }

            return qrcode.ToString();
        }


        public static byte[] Decode(string qrcode)
        {
            int total_chars = qrcode.Length;
            List<byte> decoded_bytes = new List<byte>();

            for (int i = 0; i < total_chars; i += MAX_ENCODED_BYTES_IN_CHUNK)
            {
                int chars_in_chunk;
                if ((i + MAX_ENCODED_BYTES_IN_CHUNK) > total_chars)
                {
                    chars_in_chunk = total_chars - i;
                }
                else
                {
                    chars_in_chunk = MAX_ENCODED_BYTES_IN_CHUNK;
                }

                int value = 0;
                for (int j = i + chars_in_chunk - 1; j >= i; j--)
                {
                    value = value * RADIX + Array.IndexOf(CODES, qrcode[j]);
                }

                int bytes_in_chunk = Array.IndexOf(BASE38_CHARS_NEEDED_IN_CHUNK, chars_in_chunk) + 1;
                for (int k = 0; k < bytes_in_chunk; k++)
                {
                    decoded_bytes.Add((byte)(value & 0xFF));
                    value >>= 8;
                }
            }

            return decoded_bytes.ToArray();
        }


        public static (int Padding, int Pincode, int Discriminator, int Discovery, string Flow, int Pid, int Vid, int Version) Decode(byte[] data)
        {
            if (data == null || data.Length < 8) // 假设至少需要8字节来存储所有信息  
                throw new ArgumentException("Input data is too short.");

            int index = 0;

            // 提取padding（4位）  
            int padding = (data[index] >> 4) & 0x0F;
            index++;

            // 提取pincode（27位），可能需要跨越多个字节  
            int pincode = 0;
            pincode |= (data[index] & 0x07) << 20; // 提取前3位  
            index++;
            for (int i = 0; i < 3; i++) // 还需要3个字节来存储剩余的24位  
            {
                pincode |= (data[index] & 0xFF) << (16 - (i * 8));
                index++;
            }

            // 提取discriminator（12位）  
            int discriminator = 0;
            discriminator |= (data[index] & 0xFF) << 4; // 提取前8位  
            index++;
            discriminator |= (data[index] >> 4) & 0x0F; // 提取后4位  

            // 提取discovery（8位）  
            int discovery = (data[index] & 0x0F) << 4;
            index++;
            discovery |= (data[index] >> 4) & 0x0F;

            // 提取flow（2位）  
            int flowRaw = (data[index] & 0x03);
            string flow = Enum.GetName(typeof(FlowType), flowRaw);

            // 提取pid（16位）  
            int pid = 0;
            pid |= (data[index] & 0xF0) >> 4;
            index++;
            pid |= (data[index] & 0xFF) << 4;

            // 提取vid（16位）  
            int vid = 0;
            vid |= (data[index] & 0xFF);
            index++;
            vid |= (data[index] & 0xFF) << 8;

            // 提取version（3位）  
            int version = (data[index] >> 5) & 0x07;

            return (padding, pincode, discriminator, discovery, flow, pid, vid, version);
        }

        enum FlowType
        {
            Standard = 0,
            UserIntent = 1,
            Custom = 2
        }



    }

    //class Program
    //{
    //    static void Main(string[] args)
    //    {
    //        byte[] data = Encoding.UTF8.GetBytes("Hello, world!");
    //        string encoded = Encoder.Encode(data);
    //        Console.WriteLine(encoded);
    //    }
    //}
}
